package com.quxiu.system.service.impl;

import java.util.*;

import com.alibaba.fastjson2.JSONObject;
import com.quxiu.common.core.exception.ServiceException;
import com.quxiu.common.core.utils.DateUtils;
import com.quxiu.system.constant.BpmProcStatus;
import com.quxiu.system.domain.BpmProcGroup;
import com.quxiu.system.domain.BpmProcNode;
import com.quxiu.system.domain.BpmProcVersion;
import com.quxiu.system.domain.vo.BpmProcVo;
import com.quxiu.system.mapper.BpmProcNodeMapper;
import com.quxiu.system.mapper.BpmProcVersionMapper;
import com.quxiu.system.service.IBpmProcGroupService;
import com.quxiu.system.service.IdService;
import com.quxiu.system.utils.BpmNodeGenerate;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import com.quxiu.system.mapper.BpmProcMapper;
import com.quxiu.system.domain.BpmProc;
import com.quxiu.system.service.IBpmProcService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * 流程定义Service业务层处理
 *
 * @author quxiu
 * @date 2024-06-14
 */
@Service
public class BpmProcServiceImpl implements IBpmProcService {
    @Resource
    private IdService idService;
    @Resource
    private BpmProcMapper bpmProcMapper;
    @Resource
    private BpmProcVersionMapper bpmProcVersionMapper;
    @Resource
    private BpmProcNodeMapper bpmProcNodeMapper;
    @Resource
    private IBpmProcGroupService bpmProcGroupService;


    /**
     * 查询流程定义
     *
     * @param procId 流程定义主键
     * @return 流程定义
     */
    @Override
    public BpmProcVo selectBpmProcByProcId(Long procId) {
        BpmProc proc = bpmProcMapper.selectBpmProcByProcId(procId);
        if (proc == null) {
            throw new ServiceException("无效的流程id");
        }
        BpmProcVersion version = bpmProcVersionMapper.selectByVersionId(proc.getLastVersionId());
        if (version == null) {
            throw new ServiceException("获取最新版本流程信息异常");
        }

        return this.mergeProcVo(proc, version);
    }

    @Override
    public BpmProcVo selectBpmProcByVersionId(Long versionId) {

        BpmProcVersion version = bpmProcVersionMapper.selectByVersionId(versionId);
        if (version == null) {
            throw new ServiceException("获取最新版本流程信息异常");
        }

        BpmProc proc = bpmProcMapper.selectBpmProcByProcId(version.getProcId());
        if (proc == null) {
            throw new ServiceException("无效的流程id");
        }

        return this.mergeProcVo(proc, version);
    }

    private BpmProcVo mergeProcVo(BpmProc proc, BpmProcVersion version) {
        BpmProcVo vo = new BpmProcVo();
        vo.setProcId(proc.getProcId());
        vo.setProcName(proc.getProcName());
        vo.setLastVersionId(proc.getLastVersionId());
        vo.setStatus(proc.getStatus());
        vo.setGroupId(proc.getGroupId());
        vo.setIcon(proc.getIcon());
        vo.setRemark(proc.getRemark());
        if (version.getFormConfig() != null) {
            vo.setFormConfig(JSONObject.parseObject(version.getFormConfig()));
        }
        if (version.getNodeConfig() != null) {
            vo.setNodeConfig(JSONObject.parseObject(version.getNodeConfig()));
        }
        vo.setAllowAddSign(version.getAllowAddSign());
        vo.setAllowAutoApprove(version.getAllowAutoApprove());
        vo.setAllowForward(version.getAllowForward());
        vo.setAllowRollback(version.getAllowRollback());
        vo.setAllowOpinionEmpty(version.getAllowOpinionEmpty());
        vo.setAllowRevoke(version.getAllowRevoke());
        return vo;
    }

    /**
     * 查询流程定义列表
     *
     * @param bpmProc 流程定义
     * @return 流程定义
     */
    @Override
    public List<BpmProc> selectBpmProcList(BpmProc bpmProc) {
        List<BpmProc> list = bpmProcMapper.selectBpmProcList(bpmProc);
        if (CollectionUtils.isNotEmpty(list)) {
            Map<Long, String> groupMap = bpmProcGroupService.getGroupMap();
            list.forEach(item -> {
                item.setGroupName(groupMap.get(item.getGroupId()));
            });
        }
        return list;
    }

    /**
     * 新增流程定义
     *
     * @param params 流程定义
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertBpmProc(BpmProcVo params) {
        BpmProc bpmProc = new BpmProc();
        bpmProc.setProcId(idService.nextId());
        bpmProc.setProcName(params.getProcName());
        bpmProc.setGroupId(params.getGroupId());
        bpmProc.setIcon(params.getIcon());
        bpmProc.setRemark(params.getRemark());
        bpmProc.setStatus(BpmProcStatus.enable.getCode());
        bpmProc.setCreateBy(params.getOptUserId());
        bpmProc.setCreateTime(DateUtils.getNowDate());

        // 创建流程版本
        Long versionId = this.createProcVersion(bpmProc.getProcId(), params);
        bpmProc.setLastVersionId(versionId);
        bpmProcMapper.insertBpmProc(bpmProc);


        // 创建流程节点
        this.createProcNode(bpmProc.getProcId(), versionId, params.getNodeConfig());
    }

    /**
     * 修改流程定义
     *
     * @param params 流程定义
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBpmProc(BpmProcVo params) {
        BpmProc bpmProc = new BpmProc();
        bpmProc.setProcId(params.getProcId());
        bpmProc.setProcName(params.getProcName());
        bpmProc.setGroupId(params.getGroupId());
        bpmProc.setUpdateBy(params.getOptUserId());
        bpmProc.setUpdateTime(DateUtils.getNowDate());
        // 创建流程版本
        Long versionId = this.createProcVersion(bpmProc.getProcId(), params);
        bpmProc.setLastVersionId(versionId);
        bpmProcMapper.updateBpmProc(bpmProc);

        // 创建流程节点
        this.createProcNode(bpmProc.getProcId(), versionId, params.getNodeConfig());
    }

    /**
     * 创建流程版本
     * @param procId
     * @param params
     */
    private Long createProcVersion(Long procId, BpmProcVo params) {
        BpmProcVersion version = new BpmProcVersion();
        version.setVersionId(idService.nextId());
        version.setProcId(procId);
        version.setFormConfig(params.getFormConfig().toJSONString());
        version.setNodeConfig(params.getNodeConfig().toJSONString());
        version.setAllowAddSign(params.getAllowAddSign());
        version.setAllowAutoApprove(params.getAllowAutoApprove());
        version.setAllowForward(params.getAllowForward());
        version.setAllowRollback(params.getAllowRollback());
        version.setAllowOpinionEmpty(params.getAllowOpinionEmpty());
        version.setAllowRevoke(params.getAllowRevoke());
        version.setCreateBy(params.getOptUserId());
        version.setCreateTime(DateUtils.getNowDate());
        bpmProcVersionMapper.insertBpmProcVersion(version);
        return version.getVersionId();
    }

    /**
     * 创建流程节点
     * @param procId 流程定义id
     * @param versionId 流程版本id
     * @param nodeConfig 节点配置
     */
    private void createProcNode(Long procId, Long versionId, JSONObject nodeConfig) {
        BpmNodeGenerate generate = new BpmNodeGenerate(idService, procId, versionId, nodeConfig);
        List<BpmProcNode> nodes = generate.generate();
        if (CollectionUtils.isEmpty(nodes)) {
            throw new ServiceException("无效的流程节点配置！");
        }
        bpmProcNodeMapper.insertBatchBpmProcNode(nodes);
    }

    /**
     * 递归创建流程节点
     */
    /*private void generateProcNodes(Long procId, Long versionId, List<BpmProcNode> nodes, Long parentId, Long routerId, JSONObject nodeConfig) {
        if (nodeConfig != null) {
            BpmProcNode node = new BpmProcNode();
            node.setNodeId(idGenerator.nextId());
            node.setParentId(parentId == null ? 0L : parentId);
            node.setRouterId(routerId);
            node.setProcId(procId);
            node.setVersionId(versionId);
            node.setNodeName(nodeConfig.getString("nodeName"));
            node.setNodeType(nodeConfig.getString("nodeType"));
            JSONObject config = nodeConfig.getJSONObject("config");
            if (config != null) {
                node.setConfig(config.toJSONString());
            }
            nodes.add(node);


            // 递归创建子节点
            JSONObject childNode = nodeConfig.getJSONObject("childNode");
            if (childNode != null) {
                generateProcNodes(procId, versionId, nodes, node.getNodeId(), node.getRouterId(), childNode);
            } else {

            }

            // 如果是路由节点，则递归创建分支子节点
            if (BpmNodeType.ROUTER.equals(node.getNodeType())) {
                JSONArray conditionNodes = nodeConfig.getJSONArray("conditionNodes");
                if (conditionNodes != null) {
                    for (int i = 0; i < conditionNodes.size(); i++) {
                        JSONObject conditionNode = conditionNodes.getJSONObject(i);
                        generateProcNodes(procId, versionId, nodes, node.getNodeId(), node.getNodeId(), conditionNode);
                    }
                }
            }

        }
    }
    */
    /**
     * 删除流程定义信息
     *
     * @param procId 流程定义主键
     * @return 结果
     */
    @Override
    public int deleteBpmProcByProcId(Long procId) {
        return bpmProcMapper.deleteBpmProcByProcId(procId);
    }

    @Override
    public Map<String, List<BpmProc>> getProcForGroup() {
        Map<String, List<BpmProc>> map = new LinkedHashMap<>();
        List<BpmProcGroup> groups = bpmProcGroupService.selectBpmProcGroupList(new BpmProcGroup());
        BpmProc procParam = new BpmProc();
        procParam.setStatus(BpmProcStatus.enable.getCode());
        List<BpmProc> procs = bpmProcMapper.selectBpmProcList(procParam);
        if (CollectionUtils.isNotEmpty(groups)) {
            for (BpmProcGroup group : groups) {
                List<BpmProc> list = new ArrayList<>();
                Iterator<BpmProc> iterator = procs.iterator();
                while (iterator.hasNext()) {
                    BpmProc proc = iterator.next();
                    if (group.getGroupId().equals(proc.getGroupId())) {
                        list.add(proc);
                        iterator.remove();
                    }
                }
                map.put(group.getGroupName(), list);
            }
        }

        if (CollectionUtils.isNotEmpty(procs)) {
            map.put("未分组", procs);
        }

        return map;
    }
}
